<template>
  <div class="w-full h-full flex flex-col">
    <!-- 拖拽区域 = 画布区域 -->
    <div
      class="w-full h-full flex flex-col border-3 border-dashed transition-colors duration-200"
      :class="isDragOver ? 'border-blue-400 bg-blue-50' : 'border-transparent bg-white'"
      @dragover.prevent="onDragOver"
      @dragleave="onDragLeave"
      @drop="onDrop"
    >
      <!-- 画布容器 -->
      <div class="w-full h-full relative overflow-auto bg-[#f6f7fb] cflex">
        <canvas ref="canvasRef" class="block mx-auto my-4 shadow-lg"></canvas>
        <div v-if="!fabricCanvas" class="text-[#909399] absolute text-xs 2xl:text-base">
          将左侧图片拖拽到此处，支持勾选多张一起拖入，图片可重叠摆放
        </div>
      </div>
      <!-- 隐藏的图片，用来触发 ant-design-vue 内置预览 -->
      <a-image
        :style="{ display: 'none' }"
        :preview="{
          visible,
          onVisibleChange: setVisible
        }"
        :src="previewImage"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { Canvas, FabricImage, Rect } from 'fabric'
import { useCameraStore } from '@renderer/stores/camera'
import { useImageStore } from '@renderer/stores/image'
import { message } from 'ant-design-vue'

type Cam = {
  id: number
  ip: string
  pic: string
  processedImg: string
  isChecked?: boolean
}

const cameraStore = useCameraStore()
const cameras = cameraStore.cameras

const imageStore = useImageStore()

// 兼容父组件传入的 v-model（此实现不再在主区域显示缩略列表）
const draggedCamera = defineModel<any>('draggedCamera')
const droppedCamera = defineModel<any>('droppedCamera')
const showCamera = defineModel<any>('curCamera')

// 状态
const isDragOver = ref(false)

// Fabric
const canvasRef = ref<HTMLCanvasElement | null>(null)
let fabricCanvas: Canvas | null = null
let canvasWidth = innerWidth - 600
let canvasHeight = innerHeight - 300

// 更新画布尺寸的函数
const updateCanvasSize = () => {
  const newWidth = innerWidth - 600
  const newHeight = innerHeight - 300
  canvasWidth = newWidth
  canvasHeight = newHeight
  if (fabricCanvas) {
    fabricCanvas.setDimensions({
      width: newWidth,
      height: newHeight
    })
    // 可选：重新居中所有内容或调整视图
    fabricCanvas.renderAll()
  }
}

// 拖拽
function onDragOver() {
  isDragOver.value = true
}
function onDragLeave() {
  isDragOver.value = false
}
function onDrop() {
  isDragOver.value = false
  // 勾选的批量；否则使用当前拖拽项
  const checked: Cam[] = cameras.filter((c: Cam) => c.isChecked)
  const toAdd: Cam[] = checked.length ? checked : draggedCamera.value ? [draggedCamera.value] : []
  toAdd.forEach(addImageToCanvas)
  // 同步外部（保持原有数据流，但不在本区域展示侧栏）
  if (toAdd.length) {
    droppedCamera.value = toAdd[0]
    showCamera.value = toAdd[0]
  }
}

// 初始化 Fabric
async function initFabricCanvas() {
  if (!canvasRef.value) return
  fabricCanvas = new Canvas(canvasRef.value, {
    width: canvasWidth,
    height: canvasHeight,
    backgroundColor: '#ffffff',
    selection: true,
    preserveObjectStacking: true
  })
}

// 添加图片到画布（允许重叠）
async function addImageToCanvas(cam: Cam) {
  if (!fabricCanvas) return
  const src = cam.processedImg || cam.pic
  try {
    const img = await FabricImage.fromURL(src)
    img.set({
      left: canvasWidth / 3,
      top: canvasHeight / 3,
      selectable: true,
      hasControls: true,
      hasBorders: true,
      data: { cameraId: cam.id }
    })
    // 限制尺寸
    const maxSize = Math.min(canvasWidth, canvasHeight) * 0.5
    if (img.width! > maxSize || img.height! > maxSize) {
      const s = Math.min(maxSize / img.width!, maxSize / img.height!)
      img.scale(s)
    }
    fabricCanvas.add(img)
    fabricCanvas.setActiveObject(img)
    fabricCanvas.renderAll()
  } catch (e) {
    console.error('添加图片失败:', e)
  }
}

// 清空/尺寸/导出/选择
function clearCanvas() {
  if (!fabricCanvas) return
  fabricCanvas.clear()
  fabricCanvas.backgroundColor = '#ffffff'
  fabricCanvas.renderAll()
}

function saveCanvas() {
  // 获取所有对象的范围
  const objs = fabricCanvas!.getObjects()
  const bounds = objs.reduce(
    (acc, obj) => {
      const rect = obj.getBoundingRect()
      acc.left = Math.min(acc.left, rect.left)
      acc.top = Math.min(acc.top, rect.top)
      acc.right = Math.max(acc.right, rect.left + rect.width)
      acc.bottom = Math.max(acc.bottom, rect.top + rect.height)
      return acc
    },
    { left: Infinity, top: Infinity, right: -Infinity, bottom: -Infinity }
  )

  const width = bounds.right - bounds.left
  const height = bounds.bottom - bounds.top

  if (!fabricCanvas) return
  const oldBg = fabricCanvas.backgroundColor
  fabricCanvas.backgroundColor = ''
  imageStore.pushImage(
    fabricCanvas!.toDataURL({
      left: bounds.left,
      top: bounds.top,
      width,
      height,
      format: 'png',
      multiplier: 1,
      enableRetinaScaling: true
    })
  )
  fabricCanvas.backgroundColor = oldBg
  message.success('保存成功！')
}

function exportCanvas() {
  if (!fabricCanvas) return
  const dataUrl = exportCanvasTransparent()
  const a = document.createElement('a')
  a.download = '拼接图.png'
  a.href = dataUrl
  a.click()
}

function deleteSelected() {
  if (!fabricCanvas) return
  fabricCanvas.getActiveObjects().forEach((o) => fabricCanvas!.remove(o))
  fabricCanvas.discardActiveObject()
  fabricCanvas.renderAll()
}

function exportCanvasTransparent() {
  if (!fabricCanvas) return
  const oldBg = fabricCanvas.backgroundColor
  fabricCanvas.backgroundColor = ''
  const dataUrl = fabricCanvas.toDataURL()
  fabricCanvas.backgroundColor = oldBg
  return dataUrl
}

// 预览状态
const visible = ref(false)
const previewImage = ref<string>('')

// 控制预览
const setVisible = (value: boolean): void => {
  visible.value = value
}

// 预览方法
function previewResult() {
  const dataUrl = exportCanvasTransparent()
  if (dataUrl) {
    previewImage.value = dataUrl
    setVisible(true)
  }
}

// 裁剪相关
const cropping = ref(false)
let cropRect: Rect | null = null
let cropTarget: any = null // 当前要裁剪的图片对象

// 框选范围按钮
function startCrop() {
  if (!fabricCanvas) return
  // 只允许选中一个图片对象
  const active = fabricCanvas.getActiveObject()
  if (!active || active.type !== 'image') {
    message.warning('请先选中一张图片进行裁剪')
    return
  }
  cropping.value = true
  cropTarget = active

  // 计算图片中心区域默认裁剪框
  const imgLeft = active.left ?? 0
  const imgTop = active.top ?? 0
  const imgW = active.getScaledWidth()
  const imgH = active.getScaledHeight()
  const rectW = imgW * 0.6
  const rectH = imgH * 0.6
  const rectLeft = imgLeft + (imgW - rectW) / 2
  const rectTop = imgTop + (imgH - rectH) / 2

  cropRect = new Rect({
    left: rectLeft,
    top: rectTop,
    width: rectW,
    height: rectH,
    fill: 'rgba(0,0,0,0.1)',
    stroke: '#409eff',
    strokeWidth: 2,
    selectable: true,
    hasBorders: true,
    hasControls: true,
    lockRotation: true,
    objectCaching: false,
    // 让裁剪框在最上层
    evented: true
  })
  fabricCanvas.add(cropRect)
  fabricCanvas.setActiveObject(cropRect)
  fabricCanvas.renderAll()
}

// 应用裁剪
async function applyCrop() {
  if (!fabricCanvas || !cropRect || !cropTarget) return
  const img = cropTarget

  // 画布 → 裁剪框像素
  const rect = cropRect.getBoundingRect() // true = 考虑缩放/旋转

  // 临时 Canvas 裁剪
  const tempCanvas = document.createElement('canvas')
  tempCanvas.width = rect.width
  tempCanvas.height = rect.height
  const ctx = tempCanvas.getContext('2d')!

  ctx.drawImage(
    img._element, // 原生 <img>
    (rect.left - img.left!) / img.scaleX!, // 源图裁剪起点 X
    (rect.top - img.top!) / img.scaleY!, // 源图裁剪起点 Y
    rect.width / img.scaleX!, // 裁剪宽（源图单位）
    rect.height / img.scaleY!, // 裁剪高（源图单位）
    0,
    0,
    rect.width,
    rect.height
  )

  // 生成新 Fabric Image 替换原来的
  const newImg = await FabricImage.fromURL(tempCanvas.toDataURL())
  newImg.set({
    left: rect.left,
    top: rect.top
  })

  fabricCanvas.remove(img)
  fabricCanvas.remove(cropRect)
  fabricCanvas.add(newImg)
  fabricCanvas.setActiveObject(newImg)
  fabricCanvas.renderAll()

  cropping.value = false
  cropRect = null
  cropTarget = null
}

// 取消裁剪
function cancelCrop() {
  if (!fabricCanvas || !cropRect) return
  fabricCanvas.remove(cropRect)
  fabricCanvas.renderAll()
  cropping.value = false
  cropRect = null
  cropTarget = null
}

// 生命周期
onMounted(async () => {
  await nextTick()
  await initFabricCanvas()
  window.addEventListener('resize', updateCanvasSize)
})
onBeforeUnmount(() => {
  fabricCanvas?.dispose()
  fabricCanvas = null
  window.removeEventListener('resize', updateCanvasSize)
})

// 暴露（父组件可能会调用）
defineExpose({
  exportCanvas,
  clearCanvas,
  deleteSelected,
  startCrop,
  applyCrop,
  cancelCrop,
  saveCanvas,
  previewResult
})
</script>

<style scoped></style>
